using System.Data;
using System.Data.Odbc;
using System.Xml;
using Chaotic.DataBase.DataAccess;
using Chaotic.DataBase.DataAccess.Entity;

namespace Chaotic.DataBase.ODBCAccess;

public class OdbcDataAccess : AbstractDataAccess
{
	private readonly OdbcConnection _mDbConnection;

	private OdbcTransaction? _trans;

	public override DatabaseType DatabaseType => DatabaseType.ODBC;

	public override IDbConnection DbConnection => _mDbConnection;

	public OdbcDataAccess(string connectionString)
	{
		_mDbConnection = new OdbcConnection(connectionString);
		int num = connectionString.ToLower().IndexOf("uid=", StringComparison.Ordinal) + "uid=".Length;
		int num2 = connectionString.IndexOf(';', num);
		base.Owner = connectionString.Substring(num, num2 - num).ToUpper();
	}

	public override IDbTransaction? BeginTransaction()
	{
		_trans = _mDbConnection.BeginTransaction();
		return _trans;
	}

	public override int ExecuteNonQuery(CommandType commandType, string? commandText, QueryParameterCollection commandParameters, DataRow row, SqlStruct sqlStruct)
	{
		int tmpValue = 0;
		LogOutPut(delegate
		{
			OdbcCommand odbcCommand = new OdbcCommand();
			if (sqlStruct == null)
			{
				PrepareCommand(odbcCommand, commandType, commandText, commandParameters);
			}
			else
			{
				ParamField[] paramFields = sqlStruct.ParamFields;
				foreach (ParamField paramField in paramFields)
				{
					if (paramField.ParamName.IndexOf('_') != 1)
					{
						commandParameters.Add(paramField.ParamName, row[paramField.FieldName]);
					}
					else
					{
						commandParameters.Add(paramField.ParamName, row[paramField.FieldName, DataRowVersion.Original]);
					}
				}
				PrepareCommand(odbcCommand, CommandType.Text, sqlStruct.SqlString, commandParameters);
			}
			tmpValue = odbcCommand.ExecuteNonQuery();
			odbcCommand.Parameters.Clear();
			return tmpValue;
		}, "ExecuteNonQuery", commandText, commandParameters);
		return tmpValue;
	}

	public override DataSet? ExecuteDataset(CommandType commandType, string? commandText, QueryParameterCollection commandParameters, DataSet? ds, string tableName)
	{
		LogOutPut(delegate
		{
			OdbcCommand odbcCommand = new OdbcCommand();
			PrepareCommand(odbcCommand, commandType, commandText, commandParameters);
			OdbcDataAdapter odbcDataAdapter = new OdbcDataAdapter(odbcCommand);
			if (object.Equals(tableName, null) || tableName.Length < 1)
			{
				odbcDataAdapter.Fill(ds);
			}
			else
			{
				odbcDataAdapter.Fill(ds, tableName);
			}
			odbcCommand.Parameters.Clear();
			return (ds != null && ds.Tables.Count > 0) ? ds.Tables[0].Rows.Count : 0;
		}, "ExecuteDataset", commandText, commandParameters);
		return ds;
	}

	public override DataSet? ExecuteDataset(string? commandText, QueryParameterCollection commandParameters, DataSet? ds, int startRecord, int maxRecords, string tableName)
	{
		LogOutPut(delegate
		{
			OdbcCommand odbcCommand = new OdbcCommand();
			PrepareCommand(odbcCommand, CommandType.Text, commandText, commandParameters);
			OdbcDataAdapter odbcDataAdapter = new OdbcDataAdapter(odbcCommand);
			if (object.Equals(tableName, null) || tableName.Trim() == string.Empty)
			{
				odbcDataAdapter.Fill(ds);
			}
			else
			{
				odbcDataAdapter.Fill(ds, startRecord, maxRecords, tableName);
			}
			odbcCommand.Parameters.Clear();
			return (ds != null && ds.Tables.Count > 0) ? ds.Tables[0].Rows.Count : 0;
		}, "ExecuteDataset", commandText, commandParameters);
		return ds;
	}

	public override IDataReader ExecuteReader(CommandType commandType, string? commandText, QueryParameterCollection commandParameters)
	{
		IDataReader dr = null;
		LogOutPut(delegate
		{
			OdbcCommand odbcCommand = new OdbcCommand();
			PrepareCommand(odbcCommand, commandType, commandText, commandParameters);
			dr = odbcCommand.ExecuteReader();
			odbcCommand.Parameters.Clear();
			return -1;
		}, "ExecuteReader", commandText, commandParameters);
		return dr;
	}

	public override object? ExecuteScalar(CommandType commandType, string? commandText, QueryParameterCollection commandParameters)
	{
		object? tmpValue = null;
		LogOutPut(delegate
		{
			OdbcCommand odbcCommand = new OdbcCommand();
			PrepareCommand(odbcCommand, commandType, commandText, commandParameters);
			tmpValue = odbcCommand.ExecuteScalar();
			odbcCommand.Parameters.Clear();
			return -1;
		}, "ExecuteScalar", commandText, commandParameters);
		return tmpValue;
	}

	public override XmlReader ExecuteXmlReader(CommandType commandType, string? commandText, QueryParameterCollection commandParameters)
	{
		return null;
	}

	private void PrepareCommand(OdbcCommand cmd, CommandType commandType, string? commandText, QueryParameterCollection commandParameters)
	{
		commandText = commandText.Replace(":", "@");
		cmd.CommandType = commandType;
		cmd.CommandText = commandText;
		cmd.Connection = _mDbConnection;
		cmd.Transaction = _trans;
		if (commandParameters != null && commandParameters.Count > 0)
		{
			for (int i = 0; i < commandParameters.Count; i++)
			{
				cmd.Parameters.AddWithValue(commandParameters[i].ParameterName, commandParameters[i].Value);
				cmd.Parameters[i].Direction = commandParameters[i].Direction;
			}
		}
	}

	public override void FillingTables(List<TableInfo>? info)
	{
		DataTable schema = _mDbConnection.GetSchema("Tables");
		info.AddRange(from DataRow row in schema.Rows
			where row["TABLE_TYPE"].ToString() == "TABLE"
			select new TableInfo
			{
				TableName = row["TABLE_NAME"].ToString()
			});
	}

	public override void FillingColumns(List<ColumnInfo> info)
	{
		DataTable schema = _mDbConnection.GetSchema("Columns");
		info.AddRange(from DataRow row in schema.Rows
			select new ColumnInfo
			{
				TableName = row["TABLE_NAME"].ToString(),
				ColumnName = row["COLUMN_NAME"].ToString(),
				ColumnIndex = Convert.ToInt32(row["ORDINAL_POSITION"].ToString()),
				IsNull = (row["IS_NULLABLE"].ToString().ToUpper() == "YES"),
				TypeName = row["TYPE_NAME"].ToString(),
				Length = row["COLUMN_SIZE"].ToString()
			});
	}

	public override void FillingIndexs(List<IndexInfo>? info)
	{
	}

	public override void FillingRelations(List<RelationshipInfo>? info)
	{
	}

	public override void FillingViews(List<ViewInfo> info)
	{
		DataTable schema = _mDbConnection.GetSchema("Views");
		info.AddRange(from DataRow row in schema.Rows
			where row["TABLE_SCHEM"].ToString() == base.Owner
			select new ViewInfo
			{
				ViewName = row["TABLE_NAME"].ToString()
			});
	}

	public override void FillingProcs(List<ProcInfo> info)
	{
		DataTable schema = _mDbConnection.GetSchema("Procedures");
		info.AddRange(from DataRow row in schema.Rows
			where row["PROCEDURE_SCHEM"].ToString() == base.Owner
			select new ProcInfo
			{
				ProcId = row["PROCEDURE_NAME"].ToString(),
				ProcName = row["PROCEDURE_NAME"].ToString()
			});
	}

	public override void FillingProcParams(List<ProcParamInfo> info)
	{
		DataTable schema = _mDbConnection.GetSchema("ProcedureParameters");
		info.AddRange(from DataRow row in schema.Rows
			where row["PROCEDURE_SCHEM"].ToString() == base.Owner
			select new ProcParamInfo
			{
				ProcId = row["PROCEDURE_NAME"].ToString(),
				ProcParamName = row["COLUMN_NAME"].ToString(),
				TypeName = row["TYPE_NAME"].ToString(),
				Length = row["COLUMN_SIZE"].ToString(),
				ParamIndex = Convert.ToInt32(row["ORDINAL_POSITION"].ToString()),
				DataScale = row["DECIMAL_DIGITS"].ToString()
			});
	}

	public override void FillingTypeInfos(List<TypeNameInfos> info)
	{
		DataTable schema = _mDbConnection.GetSchema("DataTypes");
		if (schema != null && schema.Rows.Count > 0)
		{
			info.AddRange(from DataRow row in schema.Rows
				select new TypeNameInfos
				{
					TypeName = row["TypeName"].ToString()
				});
		}
	}
}
